package com.weimob.mcloud.wechatwork.customer.mq.handler.externaluser.retry;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.weimob.dq.client.api.DqFramework;
import com.weimob.mcloud.wechatwork.core.adapter.enums.bos.MigrationStatus;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.ec.response.BatchMigrationStatusVo;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.retry.CustomerMsgRetry;
import com.weimob.mcloud.wechatwork.core.enums.customer.MsgStatusRetryEnum;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerService;
import com.weimob.mcloud.wechatwork.customer.config.DqConfig;
import com.weimob.mcloud.wechatwork.customer.domain.ArtemisBaseInfo;
import com.weimob.mcloud.wechatwork.customer.domain.ArtemisConstant;
import com.weimob.mcloud.wechatwork.customer.domain.ExternalUserChangeInfo;
import com.weimob.mcloud.wechatwork.customer.domain.enums.CorpExternaluserChangEventEnum;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.adapter.EcAdapterServiceProxy;
import com.weimob.mcloud.wechatwork.customer.service.impl.ArtemisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author yuanhao
 * @date 2022/12/22 15:38
 */
@Component
@Slf4j
public class AddExternalUserRetry {

    @Autowired
    private DqFramework dqClient;

    @Autowired
    private EcAdapterServiceProxy ecAdapterServiceProxy;

    @Value("${customer.search.delaytime:120}")
    private Integer customerSearchDelaytime;

    @Value("${customer.search.retrycount:2}")
    private Integer customerSearchRetryCount;

    @Value("${customer.wid.job.retry.count:2}")
    private Integer widJobRetryCount;

    @Reference
    private CustomerService customerService;

    @Autowired
    private ArtemisService artemisService;


    /**
     * wid未获取到进行重试
     *
     * @param externalUserChangeInfo externalUserChangeInfo
     * @param privateSphere          privateSphere
     */
    public void addExternalUserRetry(ExternalUserChangeInfo externalUserChangeInfo, PrivateSphere privateSphere) {
        if (Objects.isNull(externalUserChangeInfo) || Objects.isNull(privateSphere)) {
            log.error("addExternalUserRetry param valid failed");
            return;
        }

        Long bosId = privateSphere.getBosId();
        String externalUserId = externalUserChangeInfo.getExternalUserID();
        String userId = externalUserChangeInfo.getUserID();
        if (StringUtils.isBlank(externalUserId) || StringUtils.isBlank(userId)) {
            log.error("腾讯侧userId or externalUserId is null,externalUserChangeInfo：{}", JSON.toJSON(externalUserChangeInfo));
            return;
        }

        //迁移状态校验，迁移未完成则不处理
        BatchMigrationStatusVo migrationStatusVO = ecAdapterServiceProxy.getMigrationStatusVO(bosId);
        if (Objects.nonNull(migrationStatusVO) && !MigrationStatus.FINISHED.getCode().equals(migrationStatusVO.getStatus())) {
            String reason = "迁移未完成，状态：" + MigrationStatus.getByCode(migrationStatusVO.getStatus()).getDesc();
            saveRetryRecord(reason, MsgStatusRetryEnum.FAILED.getCode(), externalUserChangeInfo);
            return;
        }
        externalUserChangeInfo.setBosId(bosId);
        externalUserChangeInfo.setRetryFlag(true);
        Integer retryCount = externalUserChangeInfo.getRetryCount();
        if (retryCount == null || retryCount == 0) {
            externalUserChangeInfo.setRetryCount(1);
        } else {
            externalUserChangeInfo.setRetryCount(retryCount + 1);
        }
        if (externalUserChangeInfo.getRetryCount() > customerSearchRetryCount) {
            //大于重试次数时，不再进行重试，插入到db，交给job去处理
            log.warn("wid未换取到,重试{}次,externalUserId:{}，记录到重试记录表", customerSearchRetryCount, externalUserId);
            //保存到db
            saveRetryRecord(externalUserChangeInfo);
        } else {
            //随着次数递增，延迟时间递增
            dqClient.sendMsg(DqConfig.CUSTOMER_SEARCH_MSG_TOPIC,
                    customerSearchDelaytime * externalUserChangeInfo.getRetryCount(),
                    TimeUnit.SECONDS, JSON.toJSONString(externalUserChangeInfo),
                    null);
        }
    }


    /**
     * 记录失败的消息
     *
     * @param userChangeInfo
     */
    public void saveRetryRecord(ExternalUserChangeInfo userChangeInfo) {
        try {
            SingleRequest<CustomerMsgRetry> singleRequest = new SingleRequest<>();
            CustomerMsgRetry customerMsgRetry = new CustomerMsgRetry();
            customerMsgRetry.setCorpId(userChangeInfo.getToUserName());
            //db和延迟队列重试次数一致
            customerMsgRetry.setRetryCount(widJobRetryCount);
            customerMsgRetry.setAlreadyRetryCount(0);
            customerMsgRetry.setFailedReason("企微添加好友事件变更,消息类型：" + userChangeInfo.getChangeType());
            customerMsgRetry.setMsgJson(JSON.toJSONString(userChangeInfo));
            customerMsgRetry.setMsgStatus(MsgStatusRetryEnum.PENDING.getCode());
            customerMsgRetry.setMsgType(CorpExternaluserChangEventEnum.getCodeByChangeType(userChangeInfo.getChangeType()));
            singleRequest.setData(customerMsgRetry);
            customerService.saveUpdateRetryMsg(singleRequest);
        } catch (Exception e) {
            log.error("记录客户重试表失败，saveRetryRecord failed,error", e);
        }
    }


    /**
     * 记录失败的消息
     *
     * @param userChangeInfo
     */
    public void saveRetryRecord(String failedReason, Integer msgStatus, ExternalUserChangeInfo userChangeInfo) {
        try {
            SingleRequest<CustomerMsgRetry> singleRequest = new SingleRequest<>();
            CustomerMsgRetry customerMsgRetry = new CustomerMsgRetry();
            customerMsgRetry.setCorpId(userChangeInfo.getToUserName());
            //db和延迟队列重试次数一致
            customerMsgRetry.setRetryCount(widJobRetryCount);
            customerMsgRetry.setAlreadyRetryCount(0);
            customerMsgRetry.setFailedReason(failedReason);
            customerMsgRetry.setMsgJson(JSON.toJSONString(userChangeInfo));
            customerMsgRetry.setMsgStatus(msgStatus);
            customerMsgRetry.setMsgType(CorpExternaluserChangEventEnum.getCodeByChangeType(userChangeInfo.getChangeType()));
            singleRequest.setData(customerMsgRetry);
            customerService.saveUpdateRetryMsg(singleRequest);
        } catch (Exception e) {
            log.error("记录客户重试表失败，saveRetryRecord failed,error", e);
        }
    }


    /**
     * 记录重试
     *
     * @param externalUserChangeInfo externalUserChangeInfo
     */
    public void msgRetry(ExternalUserChangeInfo externalUserChangeInfo) {
        if (Objects.isNull(externalUserChangeInfo)) {
            log.error("addExternalUserRetry param valid failed");
            return;
        }

        String externalUserId = externalUserChangeInfo.getExternalUserID();
        externalUserChangeInfo.setRetryFlag(true);
        Integer retryCount = externalUserChangeInfo.getRetryCount();
        if (retryCount == null || retryCount == 0) {
            externalUserChangeInfo.setRetryCount(1);
        } else {
            externalUserChangeInfo.setRetryCount(retryCount + 1);
        }
        if (externalUserChangeInfo.getRetryCount() > customerSearchRetryCount) {
            //大于重试次数时，不再进行重试，插入到db，交给job去处理
            log.warn("消息处理失败,重试{}次,externalUserId:{}，记录到重试记录表", customerSearchRetryCount, externalUserId);
            //保存到db
            saveRetryRecord(externalUserChangeInfo);
        } else {
            //重新发回原队列
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("消息重试sleep报错，msgRetry error", e);
            }
            ArtemisBaseInfo<ExternalUserChangeInfo> artemisBaseInfo = new ArtemisBaseInfo<>();
            //实时消息
            artemisBaseInfo.setTopic(ArtemisConstant.Topic.WECHATWORK_SELF_MSG);
            artemisBaseInfo.setEvent(externalUserChangeInfo);
            artemisBaseInfo.setProducer(ArtemisConstant.USER);
            artemisService.sendToArtemis(artemisBaseInfo, externalUserChangeInfo.getBosId());
        }
    }

}
